#include "AReVi/Utils/memoryBlock.h"
#include "AReVi/Utils/memoryStream.h"
using namespace AReVi;

#include "event.h"
#include "element.h"
#include "fifo.h"

AR_CLASS_DEF(Event, ArObject)

Event::Event(ArCW & arCW) : ArObject(arCW) {
	_data = MemoryBlock::NEW();
	_input = MemoryIStream::NEW(_data, 0);
	_output = MemoryOStream::NEW(_data, 0);
}

Event::~Event() {
}

void Event::setEmitter(ArRef<Element> emitter) {
	_emitterID = emitter->getID();
}

unsigned int Event::getDataSize() const {
	return (_data)? _data->getSize() : 0;
}

bool Event::appendToStack(ArRef<FIFO> stack) const {
	unsigned int dataSize = _data->getSize();
	unsigned int size = _emitterID.size() + _type.size() + 2 + sizeof(unsigned int) + dataSize;
	stack->append(sizeof(unsigned int), (char *)&size);
	
	stack->append(_emitterID.size()+1, (char *)_emitterID.c_str());
	stack->append(_type.size()+1, (char *)_type.c_str());
	stack->append(sizeof(unsigned int), (char *)&dataSize);
	stack->append(dataSize, _data->accessMemory());
	return true;
}

ArRef<Event> Event::createFromStack(ArRef<FIFO> stack) {
	if (stack->getSize() < sizeof(unsigned int)) return Event::nullRef();

	unsigned int size;
	memcpy((void *) &size, (void *) stack->access(), sizeof(unsigned int));
	
	if (stack->getSize() < size) return Event::nullRef();
	stack->unstack(sizeof(unsigned int));

	ArRef<Event> evt = Event::NEW();

	char *tmp = stack->access();
	unsigned int offset = 0;
	// On lit l'id de l'émetteur
	while (*tmp) {
		evt->_emitterID += *tmp;
		tmp++;
		offset++;
	}
	// On passe au type
	tmp++;
	offset++;
	// On lit le type de l'évènement
	while (*tmp) {
		evt->_type += *tmp;
		tmp++;
		offset++;
	}

	stack->unstack(offset+1);

	// On lit la taille des données
	memcpy((void *) &size, (void *) stack->access(), sizeof(unsigned int));
	stack->unstack(sizeof(unsigned int));
	if (size) {
		// On lit les données
		evt->_data = stack->extractMB(size);
		evt->_input = MemoryIStream::NEW(evt->_data, 0);
		evt->_output = MemoryOStream::NEW(evt->_data, size);
	}

	return evt;
}

